String.prototype.trim = function() {
    var reExtraSpace = /^\s*(.*?)\s*$/;
    return this.replace(reExtraSpace, "$1");
}

var Prototype = {

    /**
     * Version of the library.
     */
    Version : '1.5.1.1',

    Browser : {
        IE : !!(window.attachEvent && !window.opera),
        Opera : !!window.opera,
        WebKit : navigator.userAgent.indexOf('AppleWebKit/') > -1,
        Gecko : navigator.userAgent.indexOf('Gecko') > -1
                && navigator.userAgent.indexOf('KHTML') == -1
    }
};

var formValidator = {
    formConfigFactory : null,
    formDealFactory : null,
    formFieldCheck : function() {
        var self = formValidator;
        if (Prototype.Browser.IE) {
            document.forms[0].onsubmit = self.initFormFieldCheck;
        } else if (Prototype.Browser.Mozilla || Prototype.Browser.Gecko) {
            document.forms[0].onsubmit = self.initFormFieldCheck;
        }
        // jFormer will add onfocus,onblur event to field, init event here.
        var self = formValidator;
        var config = self.formConfigFactory.getFormConfig();
        self.formDealFactory.addElemDealFunc(config);
    },
    initFormFieldCheck : function() {
        var self = formValidator;

        var config = self.formConfigFactory.getFormConfig();
        self.formDealFactory.addElemDealFunc(config);
        for (var i = 0; i < config.length; i++) {
            if (!config[i].dealFunc(config[i]))
                return false;
        }
        return true;
    }
};

var defaultFormConfigFactory = {
    config : null,
    cache : true,
    getFormConfig : function() {
        var self = defaultFormConfigFactory;
        if (self.cache) {
            if (!self.config) {
                self.config = self.createFormConfig();
            }
            return self.config;
        }
        return self.createFormConfig();
    },
    getElemsRange : function() { // 检查的元素范围
        return document.getElementsByTagName("*");
    },
    createFormConfig : function() {
        var self = defaultFormConfigFactory;
        return self.createFormConfigArray();
    },
    createFormConfigArray : function() {
        var self = defaultFormConfigFactory;
        var elems = self.getElemsRange();
        var array = [];
        var regexp = self.getRegExp();
        for (var i = 0; i < elems.length; i++) {
            if (elems[i].className && regexp.test(elems[i].className))
                array.push(self.createFieldConfig(elems[i]));
        }
        return array;
    },
    createFieldConfig : function(elem) {
        var self = defaultFormConfigFactory;
        var className = elem.className;
        var obj = {
            elem : elem
        };
        if (/groupRadio/i.test(className) || /groupCheck/i.test(className)) {
            obj.tipId = elem.id + "Tip";
        } else {
            obj.tipId = elem.name + "Tip";
        }

        if (/notEmp/i.test(className))
            obj.notEmp = true;
        if (/digit/i.test(className))
            obj.digit = true;
        if (/maxLen(\d+)/i.test(className))
            obj.maxLen = RegExp.$1;
        if (/groupRadio/i.test(className))
            obj.groupRadio = true;
        if (/groupCheck/i.test(className))
            obj.groupCheck = true;
        return obj;
    },
    getRegExp : function() {
        var regexp = /notEmp|digit|maxLen|groupRadio|groupCheck/i;
        return regexp;
    }
};

var defaultFormDealFactory = {
    formFieldDealFactory : null,
    addElemDealFunc : function(config) {
        var self = defaultFormDealFactory;
        for (var i = 0; i < config.length; i++)
            config[i].dealFunc = self.dealFunc;
    },
    dealFunc : function(configElem) {
        var self = defaultFormDealFactory;
        if (configElem.notEmp)
            if (!self.checkFieldEmp(configElem)) {
                return false;
            }

        if (configElem.digit)
            if (!self.checkFieldDigit(configElem)) {
                return false;
            }

        if (configElem.maxLen)
            if (!self.checkFieldLength(configElem)) {
                return false;
            }

        if (configElem.groupRadio || configElem.groupCheck)
            if (!self.checkGroup(configElem)) {
                return false;
            }
        return true;
    },
    checkFieldEmp : function(elemConfig) {
        var self = defaultFormDealFactory;
        var value = elemConfig.elem.value;
        if (value.trim() == "") {
            self.formFieldDealFactory.clewEmp(elemConfig);
            return false;
        }
        return true;
    },
    checkFieldDigit : function(elemConfig) {
        var self = defaultFormDealFactory;
        var value = elemConfig.elem.value;
        if (isNaN(value)) {
            self.formFieldDealFactory.clewDigit(elemConfig);
            return false;
        }
        return true;
    },
    checkFieldLength : function(elemConfig) {
        var self = defaultFormDealFactory;
        var value = elemConfig.elem.value;
        if (value.length > elemConfig.maxLen) {
            self.formFieldDealFactory.clewLength(elemConfig);
            return false;
        }
        return true;
    },
    checkGroup : function(elemConfig) {
        var self = defaultFormDealFactory;
        var elems = elemConfig.elem.getElementsByTagName("input");
        var i = 0;
        for (; i < elems.length; i++) {
            if (elems[i].checked)
                break;
        }
        if (i >= elems.length) {
            self.formFieldDealFactory.clewGroup(elemConfig);
            return false;
        }
        return true;
    }
};

function filterHTML(text) {
    var regexp = /<[^>]+>|\s/gi;
    return text.replace(regexp, "");
}

function defaultFormFieldMana(elem) {
    elem.focus();
    if (elem.select)
        elem.select();
}

var defaultFormFieldDealFactory = {
    formFieldMana : defaultFormFieldMana,
    clewEmp : function(elemConfig) {
        var self = defaultFormFieldDealFactory;
        alert(self.getTipText(elemConfig) + "不能为空!");
        self.checkFieldEmpFunc(elemConfig.elem);
    },
    clewDigit : function(elemConfig) {
        var self = defaultFormFieldDealFactory;
        alert(self.getTipText(elemConfig) + "必须为数值!");
        self.checkFieldDigitFunc(elemConfig.elem);
    },
    clewLength : function(elemConfig) {
        var self = defaultFormFieldDealFactory;
        alert(self.getTipText(elemConfig) + "长度不能超过" + elemConfig.maxLen + "!");
        self.checkFieldLengthFunc(elemConfig.elem);
    },
    clewGroup : function(elemConfig) {
        var self = defaultFormFieldDealFactory;
        alert(self.getTipText(elemConfig) + "不能为空!");
    },
    checkFieldEmpFunc : function(elem) {
        var self = defaultFormFieldDealFactory;
        self.formFieldMana(elem);
    },
    checkFieldDigitFunc : function(elem) {
        var self = defaultFormFieldDealFactory;
        self.checkFieldEmpFunc(elem);
    },
    checkFieldLengthFunc : function(elem) {
        var self = defaultFormFieldDealFactory;
        self.checkFieldEmpFunc(elem);
    },
    getTipText : function(config) {
        var text = document.getElementById(config.tipId).innerHTML;
        return filterHTML(text);
    }
};

//------------------ message tip, ------------------,TODO 添加onblur算法,
/**
 * depends on jQuery and jformer.css
 */
var messageTip = {
    highlight: function(elemId) {
        var wrapper = elemId + '-wrapper';
        var tip = elemId + '-tip';
        //document.getElementById(wrapper).className = "jFormComponent jFormComponentSingleLineText jFormComponentHighlight";
        document.getElementById(wrapper).className = "jFormComponent jFormComponentHighlight";
        var tipElem = document.getElementById(tip);
        tipElem.className = "jFormComponentTip jFormerTip fixed persistent active";
        tipElem.style.display = "block";
        var offset = $("#" + elemId).position();
        $("#" + tip).css({
            top: offset.top,
            left: offset.left + $("#" + elemId).outerWidth() + 4,
        });
    },
    validationFail: function(elemId) {
        var wrapper = elemId + '-wrapper';
        var tip = elemId + '-tip';
        //document.getElementById(wrapper).className = "jFormComponent jFormComponentSingleLineText jFormComponentValidationFailed";
        document.getElementById(wrapper).className = "jFormComponent jFormComponentValidationFailed";
        var tipElem = document.getElementById(tip);
        tipElem.className = "jFormComponentTip jFormerTip fixed persistent";
        tipElem.style.display = "block";
        var offset = $("#" + elemId).position();
        $("#" + tip).css({
            top: offset.top,
            left: offset.left + $("#" + elemId).outerWidth() + 4,
        });
    },
    normal: function(elemId) {
        var wrapper = elemId + '-wrapper';
        var tip = elemId + '-tip';
        //document.getElementById(wrapper).className = "jFormComponent jFormComponentSingleLineText";
        document.getElementById(wrapper).className = "jFormComponent";
        var tipElem = document.getElementById(tip);
        tipElem.className = "jFormComponentTip jFormerTip fixed persistent";
        tipElem.style.display = "none";
    },
    isValidationFail: function(elemId) {
        var wrapper = elemId + '-wrapper';
        return document.getElementById(wrapper).className.indexOf("jFormComponentValidationFailed") > -1;
    },
    dealFuncOnFocus: function(elemId) {
        var self = messageTip;
        if (!self.isValidationFail(elemId)) {
            self.highlight(elemId);
        }
    },
};
// factory,复制,粘贴即可,
var jFormerFormDealFactory = {
    formFieldDealFactory : null,
    messageTip: null,
    addElemDealFunc : function(config) {
        var self = jFormerFormDealFactory;
        for (var i = 0; i < config.length; i++) {
            config[i].dealFunc = self.dealFunc;
            if (!config[i].hasOnFocus) {
                var onFocusFunc = config[i].elem.onfocus;
                if (onFocusFunc) {
                    config[i].elem.onfocus = function(dealFactory, configElem) {
                        return function() {
                            onFocusFunc(configElem.elem);
                            dealFactory.messageTip.dealFuncOnFocus(configElem.elem.id);
                        }
                    }(self, config[i]);
                } else {
                    config[i].elem.onfocus = function(dealFactory, configElem) {
                        return function() {
                            dealFactory.messageTip.dealFuncOnFocus(configElem.elem.id);
                        }
                    }(self, config[i]);
                }
                config[i].hasOnFocus = true;
            }
            if (!config[i].hasOnBlur) {
                var onBlurFunc = config[i].elem.onblur;
                if (onBlurFunc) {
                    config[i].elem.onblur = function(dealFactory, configElem) {
                        return function() {
                            onBlurFunc(configElem.elem);
                            dealFactory.dealFuncOnBlur(configElem);
                        }
                    }(self, config[i]);
                } else {
                    config[i].elem.onblur = function(dealFactory, configElem) {
                        return function() {
                            dealFactory.dealFuncOnBlur(configElem);
                        }
                    }(self, config[i]);
                }
                config[i].hasOnBlur = true;
            }
        }
    },
    dealFunc : function(configElem) {
        var self = jFormerFormDealFactory;
        if (configElem.notEmp)
            if (!self.checkFieldEmp(configElem)) {
                return false;
            }

        if (configElem.digit)
            if (!self.checkFieldDigit(configElem)) {
                return false;
            }

        if (configElem.maxLen)
            if (!self.checkFieldLength(configElem)) {
                return false;
            }

        if (configElem.groupRadio || configElem.groupCheck)
            if (!self.checkGroup(configElem)) {
                return false;
            }
        return true;
    },
    dealFuncOnBlur: function(configElem) {
        var self = jFormerFormDealFactory;
        if (configElem.notEmp) 
            if (!self.checkFieldEmpOnBlur(configElem)) {
                return false;
            }

        if (configElem.digit)
            if (!self.checkFieldDigitOnBlur(configElem)) {
                return false;
            }

        if (configElem.maxLen)
            if (!self.checkFieldLengthOnBlur(configElem)) {
                return false;
            }

        if (configElem.groupRadio || configElem.groupCheck)
            if (!self.checkGroupOnBlur(configElem)) {
                return false;
            }
        return true;
    },
    checkFieldEmp : function(elemConfig) {
        var self = jFormerFormDealFactory;
        if (self.isFieldEmp(elemConfig)) {
            self.formFieldDealFactory.clewEmp(elemConfig);
            return false;
        }
        return true;
    },
    checkFieldEmpOnBlur: function(elemConfig) {
        var self = jFormerFormDealFactory;
        if (self.isFieldEmp(elemConfig)) {
            self.messageTip.validationFail(elemConfig.elem.id);
            return false;
        }
        self.messageTip.normal(elemConfig.elem.id);
        return true;
    },
    isFieldEmp : function(elemConfig) {
        var self = jFormerFormDealFactory;
        var value = elemConfig.elem.value;
        if (value.trim() == "")
            return true;
        return false;
    },
    checkFieldDigit : function(elemConfig) {
        var self = jFormerFormDealFactory;
        if (!self.isFieldDigit(elemConfig)) {
            self.formFieldDealFactory.clewDigit(elemConfig);
            return false;
        }
        return true;
    },
    checkFieldDigitOnBlur : function(elemConfig) {
        var self = jFormerFormDealFactory;
        if (!self.isFieldDigit(elemConfig)) {
            self.messageTip.validationFail(elemConfig.elem.id);
            return false;
        }
        self.messageTip.normal(elemConfig.elem.id);
        return true;
    },
    isFieldDigit: function(elemConfig) {
        var self = jFormerFormDealFactory;
        var value = elemConfig.elem.value;
        if (isNaN(value)) {
            return false;
        }
        return true;
    },
    checkFieldLength : function(elemConfig) {
        var self = jFormerFormDealFactory;
        if (!self.isFieldLength(elemConfig)) {
            self.formFieldDealFactory.clewLength(elemConfig);
            return false;
        }
        return true;
    },
    checkFieldLengthOnBlur : function(elemConfig) {
        var self = jFormerFormDealFactory;
        if (!self.isFieldLength(elemConfig)) {
            self.messageTip.validationFail(elemConfig.elem.id);
            return false;
        }
        self.messageTip.normal(elemConfig.elem.id);
        return true;
    },
    isFieldLength : function(elemConfig) {
        var self = jFormerFormDealFactory;
        var value = elemConfig.elem.value;
        if (value.length > elemConfig.maxLen)
            return false;
        return true;
    },
    checkGroup : function(elemConfig) {
        var self = jFormerFormDealFactory;
        if (!self.isGroup(elemConfig)) {
            self.formFieldDealFactory.clewGroup(elemConfig);
            return false;
        }
        return true;
    },
    checkGroupOnBlur : function(elemConfig) {
        var self = jFormerFormDealFactory;
        if (!self.isGroup(elemConfig)) {
            self.messageTip.validationFail(elemConfig.elem.id);
            return false;
        }
        self.messageTip.normal(elemConfig.elem.id);
        return true;
    },
    isGroup : function(elemConfig) {
        var self = jFormerFormDealFactory;
        var elems = elemConfig.elem.getElementsByTagName("input");
        var i = 0;
        for (; i < elems.length; i++) {
            if (elems[i].checked)
                break;
        }
        if (i >= elems.length) {
            return false;
        }
        return true;
    },
};
var jFormerFormFieldDealFactory = {
    formFieldMana : defaultFormFieldMana,
    messageTip: messageTip,
    clewEmp : function(elemConfig) {
        var self = jFormerFormFieldDealFactory;
        self.messageTip.validationFail(elemConfig.elem.id);
        self.checkFieldEmpFunc(elemConfig.elem);
    },
    clewDigit : function(elemConfig) {
        var self = jFormerFormFieldDealFactory;
        self.messageTip.validationFail(elemConfig.elem.id);
        self.checkFieldDigitFunc(elemConfig.elem);
    },
    clewLength : function(elemConfig) {
        var self = jFormerFormFieldDealFactory;
        self.messageTip.validationFail(elemConfig.elem.id);
        self.checkFieldLengthFunc(elemConfig.elem);
    },
    clewGroup : function(elemConfig) {
        var self = jFormerFormFieldDealFactory;
        self.messageTip.validationFail(elemConfig.elem.id);
    },
    checkFieldEmpFunc : function(elem) {
        var self = jFormerFormFieldDealFactory;
        self.formFieldMana(elem);
    },
    checkFieldDigitFunc : function(elem) {
        var self = jFormerFormFieldDealFactory;
        self.checkFieldEmpFunc(elem);
    },
    checkFieldLengthFunc : function(elem) {
        var self = jFormerFormFieldDealFactory;
        self.checkFieldEmpFunc(elem);
    },
};
//------------------ message tip ------------------

function addFormCheckOnDOMLoad() {
    initFormConfig();
    addOnDocumentLoad(formValidator.formFieldCheck);
}

function initFormConfig() {
    // 注入数据工厂和行为工厂
    formValidator.formConfigFactory = defaultFormConfigFactory;
    defaultFormDealFactory.formFieldDealFactory = defaultFormFieldDealFactory;
    formValidator.formDealFactory = defaultFormDealFactory;
}

function addJFormerFormCheckOnDOMLoad() {
    initJFormerFormConfig();
    addOnDocumentLoad(formValidator.formFieldCheck);
}

function initJFormerFormConfig() {
    // 注入数据工厂和行为工厂
    formValidator.formConfigFactory = defaultFormConfigFactory;
    jFormerFormDealFactory.formFieldDealFactory = jFormerFormFieldDealFactory;
    jFormerFormDealFactory.messageTip = messageTip;
    formValidator.formDealFactory = jFormerFormDealFactory;
}

function addOnDocumentLoad(func) {
    if (Prototype.Browser.IE) {
        document.write("<scr" + "ipt id=__ie_init defer=true "
                + "src=//:><\/script>");
        var script = document.getElementById("__ie_init");
        if (script)
            script.onreadystatechange = function() {
                if (this.readyState != "complete")
                    return;
                func();
            };
        script = null;
    } else if (Prototype.Browser.Mozilla || Prototype.Browser.Gecko) {
        document.addEventListener("DOMContentLoaded", func, false);
    }
}

